---
title: "Swift 中的函数和闭包"
description: "学习如何在 Swift 中定义和使用函数和闭包，与 JavaScript 进行直接对比。"
---

## 1. 介绍

函数和闭包是 JavaScript 和 Swift 中的基本构建块。虽然 JavaScript 将函数视为一等公民，但 Swift 带来了额外的安全性、清晰性和表达能力，特别是在类型系统和闭包语法方面。

**主要学习目标：**
- 理解 Swift 中的函数声明和用法
- 对比参数处理和返回值
- 学习闭包语法和用法
- 探索高阶函数和函数式编程模式

## 2. 函数声明和参数

### 2.1 基本函数声明

<UniversalEditor title="函数声明对比" compare={true}>
```javascript !! js
// JavaScript 函数声明
function greet(name) {
    return `Hello, ${name}!`;
}

// 箭头函数
const greetArrow = (name) => `Hello, ${name}!`;

console.log(greet("Alice"));
console.log(greetArrow("Bob"));
```

```swift !! swift
// Swift 函数声明
func greet(name: String) -> String {
    return "Hello, \(name)!"
}

print(greet(name: "Alice"))
```
</UniversalEditor>

### 2.2 参数和返回值

Swift 需要显式的参数类型和返回类型，使代码更安全、更可预测。

<UniversalEditor title="参数和返回值" compare={true}>
```javascript !! js
// JavaScript - 参数和返回值
function add(a, b) {
    return a + b;
}

function sayHello() {
    return "Hello!";
}

console.log(add(2, 3));
console.log(sayHello());
```

```swift !! swift
// Swift - 参数和返回值
func add(a: Int, b: Int) -> Int {
    return a + b
}

func sayHello() -> String {
    return "Hello!"
}

print(add(a: 2, b: 3))
print(sayHello())
```
</UniversalEditor>

### 2.3 默认参数和可变参数

<UniversalEditor title="默认参数和可变参数" compare={true}>
```javascript !! js
// JavaScript 默认参数和剩余参数
function greet(name = "World") {
    return `Hello, ${name}!`;
}

function sum(...numbers) {
    return numbers.reduce((acc, n) => acc + n, 0);
}

console.log(greet());
console.log(sum(1, 2, 3, 4));
```

```swift !! swift
// Swift 默认参数和可变参数
func greet(name: String = "World") -> String {
    return "Hello, \(name)!"
}

func sum(_ numbers: Int...) -> Int {
    return numbers.reduce(0, +)
}

print(greet())
print(sum(1, 2, 3, 4))
```
</UniversalEditor>

## 3. 闭包（匿名函数）

### 3.1 闭包语法基础

Swift 中的闭包类似于 JavaScript 的匿名函数（lambda/箭头函数），但语法更简洁、更灵活。

<UniversalEditor title="闭包语法对比" compare={true}>
```javascript !! js
// JavaScript 匿名函数和箭头函数
const add = function(a, b) {
    return a + b;
};

const multiply = (a, b) => a * b;

console.log(add(2, 3));
console.log(multiply(4, 5));
```

```swift !! swift
// Swift 闭包表达式
let add = { (a: Int, b: Int) -> Int in
    return a + b
}

let multiply: (Int, Int) -> Int = { a, b in a * b }

print(add(2, 3))
print(multiply(4, 5))
```
</UniversalEditor>

### 3.2 闭包简写语法

Swift 提供了几种更简洁的闭包写法。

<UniversalEditor title="闭包简写语法" compare={true}>
```javascript !! js
// JavaScript 箭头函数简写
const numbers = [1, 2, 3, 4, 5];

// 完整箭头函数
const doubled = numbers.map((num) => {
    return num * 2;
});

// 简写箭头函数
const tripled = numbers.map(num => num * 3);

// 更短的隐式返回
const squared = numbers.map(num => num ** 2);

console.log(doubled);
console.log(tripled);
console.log(squared);
```

```swift !! swift
// Swift 闭包简写语法
let numbers = [1, 2, 3, 4, 5]

// 完整闭包语法
let doubled = numbers.map({ (num: Int) -> Int in
    return num * 2
})

// 类型推断
let tripled = numbers.map({ num in
    return num * 3
})

// 简写参数名
let squared = numbers.map({ $0 * $0 })

// 尾随闭包语法
let filtered = numbers.filter { $0 > 2 }

print(doubled)
print(tripled)
print(squared)
print(filtered)
```
</UniversalEditor>

## 4. 高阶函数

### 4.1 Map、Filter、Reduce

Swift 的集合方法与 JavaScript 的数组方法类似，但具有更强的类型安全性。

<UniversalEditor title="高阶函数" compare={true}>
```javascript !! js
// JavaScript 数组方法
const numbers = [1, 2, 3, 4, 5, 6];

// Map
const doubled = numbers.map(num => num * 2);

// Filter
const evens = numbers.filter(num => num % 2 === 0);

// Reduce
const sum = numbers.reduce((acc, num) => acc + num, 0);

// 链式调用
const result = numbers
    .filter(num => num > 2)
    .map(num => num * 2)
    .reduce((acc, num) => acc + num, 0);

console.log(doubled);  // [2, 4, 6, 8, 10, 12]
console.log(evens);    // [2, 4, 6]
console.log(sum);      // 21
console.log(result);   // 30
```

```swift !! swift
// Swift 集合方法
let numbers = [1, 2, 3, 4, 5, 6]

// Map
let doubled = numbers.map { $0 * 2 }

// Filter
let evens = numbers.filter { $0 % 2 == 0 }

// Reduce
let sum = numbers.reduce(0, +)

// 链式调用
let result = numbers
    .filter { $0 > 2 }
    .map { $0 * 2 }
    .reduce(0, +)

print(doubled)  // [2, 4, 6, 8, 10, 12]
print(evens)    // [2, 4, 6]
print(sum)      // 21
print(result)   // 30
```
</UniversalEditor>

### 4.2 自定义高阶函数

<UniversalEditor title="自定义高阶函数" compare={true}>
```javascript !! js
// JavaScript 自定义高阶函数
function forEach(array, callback) {
    for (let i = 0; i < array.length; i++) {
        callback(array[i], i, array);
    }
}

function find(array, predicate) {
    for (let item of array) {
        if (predicate(item)) {
            return item;
        }
    }
    return undefined;
}

const numbers = [1, 2, 3, 4, 5];

forEach(numbers, (num, index) => {
    console.log(`Number ${index}: ${num}`);
});

const firstEven = find(numbers, num => num % 2 === 0);
console.log(firstEven); // 2
```

```swift !! swift
// Swift 自定义高阶函数
func forEach<T>(_ array: [T], _ callback: (T, Int) -> Void) {
    for (index, item) in array.enumerated() {
        callback(item, index)
    }
}

func find<T>(_ array: [T], _ predicate: (T) -> Bool) -> T? {
    for item in array {
        if predicate(item) {
            return item
        }
    }
    return nil
}

let numbers = [1, 2, 3, 4, 5]

forEach(numbers) { num, index in
    print("Number \(index): \(num)")
}

let firstEven = find(numbers) { $0 % 2 == 0 }
print(firstEven ?? "No even number found") // Optional(2)
```
</UniversalEditor>

## 5. 闭包捕获和内存管理

### 5.1 闭包捕获列表

Swift 的闭包捕获列表提供了对值捕获方式的显式控制，与 JavaScript 的词法作用域不同。

<UniversalEditor title="闭包捕获列表" compare={true}>
```javascript !! js
// JavaScript 闭包捕获（词法作用域）
function createCounter() {
    let count = 0;
    
    return {
        increment: () => ++count,
        decrement: () => --count,
        getCount: () => count
    };
}

const counter = createCounter();
console.log(counter.getCount()); // 0
console.log(counter.increment()); // 1
console.log(counter.increment()); // 2
console.log(counter.decrement()); // 1
```

```swift !! swift
// Swift 闭包捕获列表
func createCounter() -> (increment: () -> Int, decrement: () -> Int, getCount: () -> Int) {
    var count = 0
    
    let increment = { 
        count += 1
        return count
    }
    
    let decrement = { 
        count -= 1
        return count
    }
    
    let getCount = { count }
    
    return (increment: increment, decrement: decrement, getCount: getCount)
}

let counter = createCounter()
print(counter.getCount()) // 0
print(counter.increment()) // 1
print(counter.increment()) // 2
print(counter.decrement()) // 1
```
</UniversalEditor>

### 5.2 弱引用和无主引用

Swift 提供了对闭包中引用循环的显式控制。

<UniversalEditor title="弱引用和无主引用" compare={true}>
```javascript !! js
// JavaScript - 不需要显式弱引用
class Person {
    constructor(name) {
        this.name = name;
        this.friends = [];
    }
    
    addFriend(friend) {
        this.friends.push(friend);
        friend.friends.push(this);
    }
    
    introduce() {
        console.log(`Hi, I'm ${this.name}`);
    }
}

const alice = new Person("Alice");
const bob = new Person("Bob");
alice.addFriend(bob);
```

```swift !! swift
// Swift - 显式弱引用防止循环引用
class Person {
    let name: String
    var friends: [Person] = []
    
    init(name: String) {
        self.name = name
    }
    
    func addFriend(_ friend: Person) {
        friends.append(friend)
        friend.friends.append(self)
    }
    
    func introduce() {
        print("Hi, I'm \(name)")
    }
    
    // 使用弱引用防止循环引用
    lazy var introduceClosure: () -> Void = { [weak self] in
        guard let self = self else { return }
        print("Hi, I'm \(self.name)")
    }
}

let alice = Person(name: "Alice")
let bob = Person(name: "Bob")
alice.addFriend(bob)
```
</UniversalEditor>

## 6. 函数式编程模式

### 6.1 函数组合

<UniversalEditor title="函数组合" compare={true}>
```javascript !! js
// JavaScript 函数组合
const compose = (...fns) => x => fns.reduceRight((acc, fn) => fn(acc), x);
const pipe = (...fns) => x => fns.reduce((acc, fn) => fn(acc), x);

const addOne = x => x + 1;
const double = x => x * 2;
const square = x => x ** 2;

const composed = compose(square, double, addOne);
const piped = pipe(addOne, double, square);

console.log(composed(3)); // ((3 + 1) * 2) ^ 2 = 64
console.log(piped(3));    // ((3 + 1) * 2) ^ 2 = 64
```

```swift !! swift
// Swift 函数组合
func compose<T, U, V>(_ f: @escaping (U) -> V, _ g: @escaping (T) -> U) -> (T) -> V {
    return { f(g($0)) }
}

func pipe<T, U, V>(_ f: @escaping (T) -> U, _ g: @escaping (U) -> V) -> (T) -> V {
    return { g(f($0)) }
}

let addOne: (Int) -> Int = { $0 + 1 }
let double: (Int) -> Int = { $0 * 2 }
let square: (Int) -> Int = { $0 * $0 }

let composed = compose(square, compose(double, addOne))
let piped = pipe(addOne, pipe(double, square))

print(composed(3)) // ((3 + 1) * 2) ^ 2 = 64
print(piped(3))    // ((3 + 1) * 2) ^ 2 = 64
```
</UniversalEditor>

### 6.2 柯里化和部分应用

<UniversalEditor title="柯里化和部分应用" compare={true}>
```javascript !! js
// JavaScript 柯里化
const add = (a) => (b) => a + b;
const addFive = add(5);

console.log(addFive(3)); // 8

// 部分应用
const multiply = (a, b) => a * b;
const multiplyByTwo = multiply.bind(null, 2);

console.log(multiplyByTwo(4)); // 8
```

```swift !! swift
// Swift 柯里化
func add(_ a: Int) -> (Int) -> Int {
    return { b in a + b }
}

let addFive = add(5)
print(addFive(3)) // 8

// 使用闭包的部分应用
func multiply(_ a: Int, _ b: Int) -> Int {
    return a * b
}

let multiplyByTwo: (Int) -> Int = { multiply(2, $0) }
print(multiplyByTwo(4)) // 8
```
</UniversalEditor>

## 7. 练习

### 练习 1: 基本函数和闭包

<UniversalEditor title="练习 1: 基本函数和闭包" compare={true}>
```javascript !! js
// JavaScript 练习
function calculateArea(width, height) {
    return width * height;
}

const calculatePerimeter = (width, height) => 2 * (width + height);

function createGreeter(greeting) {
    return function(name) {
        return `${greeting}, ${name}!`;
    };
}

const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

// 过滤偶数并翻倍
const result = numbers
    .filter(num => num % 2 === 0)
    .map(num => num * 2)
    .reduce((sum, num) => sum + num, 0);

console.log(calculateArea(5, 3)); // 15
console.log(calculatePerimeter(5, 3)); // 16

const helloGreeter = createGreeter("Hello");
console.log(helloGreeter("Alice")); // "Hello, Alice!"

console.log(result); // 60 (2+4+6+8+10) * 2
```

```swift !! swift
// Swift 练习
func calculateArea(width: Int, height: Int) -> Int {
    return width * height
}

let calculatePerimeter: (Int, Int) -> Int = { width, height in
    2 * (width + height)
}

func createGreeter(greeting: String) -> (String) -> String {
    return { name in
        "\(greeting), \(name)!"
    }
}

let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

// 过滤偶数并翻倍
let result = numbers
    .filter { $0 % 2 == 0 }
    .map { $0 * 2 }
    .reduce(0, +)

print(calculateArea(width: 5, height: 3)) // 15
print(calculatePerimeter(5, 3)) // 16

let helloGreeter = createGreeter(greeting: "Hello")
print(helloGreeter("Alice")) // "Hello, Alice!"

print(result) // 60 (2+4+6+8+10) * 2
```
</UniversalEditor>

### 练习 2: 高级闭包用法

<UniversalEditor title="练习 2: 高级闭包用法" compare={true}>
```javascript !! js
// JavaScript 高级闭包练习
function createCounter(initialValue = 0) {
    let count = initialValue;
    
    return {
        increment: () => ++count,
        decrement: () => --count,
        reset: () => { count = initialValue; return count; },
        getValue: () => count
    };
}

function memoize(fn) {
    const cache = new Map();
    
    return function(...args) {
        const key = JSON.stringify(args);
        if (cache.has(key)) {
            return cache.get(key);
        }
        const result = fn.apply(this, args);
        cache.set(key, result);
        return result;
    };
}

const expensiveFunction = memoize((n) => {
    console.log(`Computing for ${n}`);
    return n * n;
});

const counter = createCounter(10);
console.log(counter.getValue()); // 10
console.log(counter.increment()); // 11
console.log(counter.increment()); // 12
console.log(counter.reset()); // 10

console.log(expensiveFunction(5)); // Computing for 5, 25
console.log(expensiveFunction(5)); // 25 (cached)
```

```swift !! swift
// Swift 高级闭包练习
func createCounter(initialValue: Int = 0) -> (increment: () -> Int, decrement: () -> Int, reset: () -> Int, getValue: () -> Int) {
    var count = initialValue
    
    let increment = {
        count += 1
        return count
    }
    
    let decrement = {
        count -= 1
        return count
    }
    
    let reset = {
        count = initialValue
        return count
    }
    
    let getValue = {
        return count
    }
    
    return (increment: increment, decrement: decrement, reset: reset, getValue: getValue)
}

func memoize<T: Hashable, U>(_ fn: @escaping (T) -> U) -> (T) -> U {
    var cache: [T: U] = [:]
    
    return { input in
        if let cached = cache[input] {
            return cached
        }
        let result = fn(input)
        cache[input] = result
        return result
    }
}

let expensiveFunction = memoize { (n: Int) -> Int in
    print("Computing for \(n)")
    return n * n
}

let counter = createCounter(initialValue: 10)
print(counter.getValue()) // 10
print(counter.increment()) // 11
print(counter.increment()) // 12
print(counter.reset()) // 10

print(expensiveFunction(5)) // Computing for 5, 25
print(expensiveFunction(5)) // 25 (cached)
```
</UniversalEditor>

## 8. 关键要点

### 8.1 函数和闭包差异

| 特性 | JavaScript | Swift | 关键差异 |
|---|---|---|---|
| **函数声明** | `function` 关键字或箭头函数 | `func` 关键字 | Swift 需要显式类型 |
| **参数类型** | 动态类型 | 静态类型 | Swift 提供编译时安全性 |
| **返回类型** | 推断 | 显式 | Swift 需要返回类型声明 |
| **闭包语法** | 箭头函数 `=>` | `{ } in` 语法 | Swift 有更灵活的语法选项 |
| **捕获列表** | 词法作用域 | 显式捕获列表 | Swift 提供更多内存控制 |
| **高阶函数** | 数组方法 | 集合方法 | 相似功能，不同语法 |

### 8.2 最佳实践

1. **使用类型注解**: 显式类型使代码更清晰、更安全
2. **优先使用尾随闭包**: 使用尾随闭包语法提高可读性
3. **使用捕获列表**: 显式控制闭包捕获以防止循环引用
4. **利用类型推断**: 当明显时让 Swift 推断类型
5. **使用函数式模式**: 利用 Swift 的函数式编程特性
6. **处理内存管理**: 适当使用弱引用和无主引用

### 8.3 常见陷阱

1. **忘记参数标签**: Swift 使用外部参数名
2. **忽略返回类型**: Swift 需要显式返回类型声明
3. **循环引用**: 在捕获 self 的闭包中不使用弱引用
4. **类型不匹配**: 不匹配闭包类型与期望的函数类型
5. **过度复杂化闭包**: 在简写更清晰时使用完整语法

## 9. 下一步

在下一个模块中，我们将探索 Swift 中的集合，包括：
- 数组、字典和集合
- 集合方法和操作
- 自定义集合类型
- 性能考虑

这个函数和闭包基础将为你准备更高级的 Swift 编程概念和 iOS 开发。 